Skip to content

Improve error output for duplicate symbol for llvm-link and lto #118712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

sivadeilra
Copy link
Contributor

When linking bitcode files (not native object files), the llvm-lto and llvm-link tools report an error when a symbol name is defined in more than one input bitcode file. Debugging this problem is difficult, because llvm-lto (and llvm-link) only shows the name of the duplicated symbol, but does not show the name of the bitcode files that contained the duplicated symbol name.

This PR adds the name of the modules that contributed the symbol to the error. This makes debugging symbol collisions easier. The PR also adds regression tests for llvm-lto and llvm-link.

Unfortunately, I did not see an easy way to get the module name for both modules that produced a symbol name collision. This PR shows the module names for both the "source" and "destination" modules, but only the "source" is an input bitcode file. The "destination" module is the output module (LTO object or linked object) that is being generated. If reviewers can suggest a way to get the information for both modules, it would be appreciated and I would update the PR.

Copy link

github-actions bot commented Dec 4, 2024

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added the LTO Link time optimization (regular/full LTO or ThinLTO) label Dec 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 4, 2024

@llvm/pr-subscribers-lto

Author: None (sivadeilra)

Changes

When linking bitcode files (not native object files), the llvm-lto and llvm-link tools report an error when a symbol name is defined in more than one input bitcode file. Debugging this problem is difficult, because llvm-lto (and llvm-link) only shows the name of the duplicated symbol, but does not show the name of the bitcode files that contained the duplicated symbol name.

This PR adds the name of the modules that contributed the symbol to the error. This makes debugging symbol collisions easier. The PR also adds regression tests for llvm-lto and llvm-link.

Unfortunately, I did not see an easy way to get the module name for both modules that produced a symbol name collision. This PR shows the module names for both the "source" and "destination" modules, but only the "source" is an input bitcode file. The "destination" module is the output module (LTO object or linked object) that is being generated. If reviewers can suggest a way to get the information for both modules, it would be appreciated and I would update the PR.


Full diff: https://github.com/llvm/llvm-project/pull/118712.diff

7 Files Affected:

  • (modified) llvm/lib/Linker/LinkModules.cpp (+15-2)
  • (added) llvm/test/LTO/X86/Inputs/duplicate1.ll (+6)
  • (added) llvm/test/LTO/X86/Inputs/duplicate2.ll (+6)
  • (added) llvm/test/LTO/X86/duplicate_symbol.test (+5)
  • (added) llvm/test/tools/llvm-link/Inputs/duplicate1.ll (+6)
  • (added) llvm/test/tools/llvm-link/Inputs/duplicate2.ll (+6)
  • (added) llvm/test/tools/llvm-link/duplicate_symbol.test (+5)
diff --git a/llvm/lib/Linker/LinkModules.cpp b/llvm/lib/Linker/LinkModules.cpp
index 485ac106d4ebb1..ef582331b30a0d 100644
--- a/llvm/lib/Linker/LinkModules.cpp
+++ b/llvm/lib/Linker/LinkModules.cpp
@@ -321,8 +321,21 @@ bool ModuleLinker::shouldLinkFromSource(bool &LinkFromSrc,
   assert(!Dest.hasExternalWeakLinkage());
   assert(Dest.hasExternalLinkage() && Src.hasExternalLinkage() &&
          "Unexpected linkage type!");
-  return emitError("Linking globals named '" + Src.getName() +
-                   "': symbol multiply defined!");
+
+  std::string message = ("Linking globals named '" + Src.getName() +
+                      "': symbol multiply defined!").str();
+  if (auto SrcParent = Src.getParent(); SrcParent != nullptr) {
+    message += " (source: ";
+    message += SrcParent->getName();
+    message += ")";
+  }
+
+  if (auto DestParent = Dest.getParent(); DestParent != nullptr) {
+    message += " (dest: ";
+    message += DestParent->getName();
+    message += ")";
+  }
+  return emitError(message);
 }
 
 bool ModuleLinker::linkIfNeeded(GlobalValue &GV,
diff --git a/llvm/test/LTO/X86/Inputs/duplicate1.ll b/llvm/test/LTO/X86/Inputs/duplicate1.ll
new file mode 100644
index 00000000000000..a5db7c17e90d18
--- /dev/null
+++ b/llvm/test/LTO/X86/Inputs/duplicate1.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @this_function_is_duplicated() {
+entry:
+  ret void
+}
diff --git a/llvm/test/LTO/X86/Inputs/duplicate2.ll b/llvm/test/LTO/X86/Inputs/duplicate2.ll
new file mode 100644
index 00000000000000..a5db7c17e90d18
--- /dev/null
+++ b/llvm/test/LTO/X86/Inputs/duplicate2.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @this_function_is_duplicated() {
+entry:
+  ret void
+}
diff --git a/llvm/test/LTO/X86/duplicate_symbol.test b/llvm/test/LTO/X86/duplicate_symbol.test
new file mode 100644
index 00000000000000..df1fb438b4c1bc
--- /dev/null
+++ b/llvm/test/LTO/X86/duplicate_symbol.test
@@ -0,0 +1,5 @@
+RUN: llvm-as %S/Inputs/duplicate1.ll -o %t.duplicate1.bc
+RUN: llvm-as %S/Inputs/duplicate2.ll -o %t.duplicate2.bc
+RUN: not llvm-lto %t.duplicate1.bc %t.duplicate2.bc -o %t.lto.obj 2>&1 | FileCheck %s
+CHECK: symbol multiply defined!
+CHECK: duplicate2
diff --git a/llvm/test/tools/llvm-link/Inputs/duplicate1.ll b/llvm/test/tools/llvm-link/Inputs/duplicate1.ll
new file mode 100644
index 00000000000000..a5db7c17e90d18
--- /dev/null
+++ b/llvm/test/tools/llvm-link/Inputs/duplicate1.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @this_function_is_duplicated() {
+entry:
+  ret void
+}
diff --git a/llvm/test/tools/llvm-link/Inputs/duplicate2.ll b/llvm/test/tools/llvm-link/Inputs/duplicate2.ll
new file mode 100644
index 00000000000000..a5db7c17e90d18
--- /dev/null
+++ b/llvm/test/tools/llvm-link/Inputs/duplicate2.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @this_function_is_duplicated() {
+entry:
+  ret void
+}
diff --git a/llvm/test/tools/llvm-link/duplicate_symbol.test b/llvm/test/tools/llvm-link/duplicate_symbol.test
new file mode 100644
index 00000000000000..4633e11e3a12a1
--- /dev/null
+++ b/llvm/test/tools/llvm-link/duplicate_symbol.test
@@ -0,0 +1,5 @@
+RUN: llvm-as %S/Inputs/duplicate1.ll -o %t.duplicate1.bc
+RUN: llvm-as %S/Inputs/duplicate2.ll -o %t.duplicate2.bc
+RUN: not llvm-link %t.duplicate1.bc %t.duplicate2.bc -o %t.duplicate.linked.bc 2>&1 | FileCheck %s
+CHECK: symbol multiply defined!
+CHECK: duplicate2

@sivadeilra
Copy link
Contributor Author

I'm working on fixing the test failure, but meanwhile would like to get guidance on whether it is possible to get the paths of both modules that caused a symbol collision.

@teresajohnson
Copy link
Contributor

I'm working on fixing the test failure, but meanwhile would like to get guidance on whether it is possible to get the paths of both modules that caused a symbol collision.

Unlikely, because these lower level LLVM mechanisms don't keep track of source modules for already merged symbols. They are really only meant for LLVM testing though. Better to use a linker for LTO linking anything real, which will give better error messages.

@sivadeilra sivadeilra closed this Aug 7, 2025
@sivadeilra sivadeilra deleted the sivadeilra-link-duplicate-symbol-error branch August 7, 2025 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LTO Link time optimization (regular/full LTO or ThinLTO) tools:llvm-link
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants